package com.spzx.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.spzx.common.core.constant.UserConstants;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.DateUtils;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.common.core.utils.http.HttpUtils;
import com.spzx.user.config.SmsConfig;
import com.spzx.user.service.SmsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class SmsServiceImpl implements SmsService {

    // 中国手机号码正则表达式
    private static final String regex = "^1[3-9]\\d{9}$";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SmsConfig smsConfig;

    @Override
    public void sendCode(String phone) {
        /*
            发送验证码前的必要校验:
            1、校验手机号格式
            2、如果该用户此前获取过验证码
                2.1、校验验证码的发送频率==>>1分钟一次
                2.2、当日只能获取5次验证码，达到5次后，当日不再发送验证码
         */
        Integer times = 1;
        if (!phone.matches(regex)) {
            throw new ServiceException("手机号格式不符合规则，请重新确认后再输入!");
        }
        BoundHashOperations<String, String, Object> hashOps = redisTemplate.boundHashOps(UserConstants.SMS_CODE + phone);
        if (CollUtil.isNotEmpty(hashOps.entries())) {
            String sendTime = (String) hashOps.get(UserConstants.HASH_KEY1);
            DateTime dateTime = DateUtil.parse(sendTime);
            long diffInMillies = System.currentTimeMillis() - dateTime.getTime();
            if (diffInMillies < 60 * 1000) {
                throw new ServiceException("请不要频繁获取验证码，一分钟之后再重新尝试。");
            }
            times = (Integer) hashOps.get(UserConstants.HASH_KEY2);
            if (DateUtil.isSameDay(dateTime, new Date()) && times >= 5) {
                throw new ServiceException("该手机号今日获取验证码的次数已耗尽，请明天再尝试。");
            }
        }
        String code = RandomUtil.randomNumbers(4);
        hashOps.put(UserConstants.HASH_KEY1, DateUtil.now());
        times += 1;
        hashOps.put(UserConstants.HASH_KEY2, times);
        hashOps.put(UserConstants.HASH_KEY3, code);
        hashOps.put(UserConstants.HASH_KEY4, "0");
        sendSms(phone, code);
    }

    /**
     * 发送短信验证码
     *
     * @param phone
     * @param code
     */
    private void sendSms(String phone, String code) {
        String host = smsConfig.getHost();
        String path = smsConfig.getPath();
        String method = "POST";
        String appcode = smsConfig.getAppCode();
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Authorization", "APPCODE " + appcode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("mobile", phone);
        querys.put("param", "**code**:" + code + ",**minute**:5");
        querys.put("smsSignId", smsConfig.getSmsSignId());
        querys.put("templateId", smsConfig.getTemplateId());
        Map<String, String> bodys = new HashMap<String, String>();
        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            log.info("验证码发送结果为：{}", response.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
